﻿using System;
using System.ComponentModel;

namespace NanoMvvm
{
    public class SelectionItemViewModel<T> : PropertyObservableBase where T : class
    {
        private readonly SelectionViewModel<T> parent;
        private bool isSelected;

        private int index;

        private bool isSelectable;

        internal SelectionItemViewModel(SelectionViewModel<T> parent, T item)
        {
            Item = item;
            this.parent = parent;
            isSelectable = true;
        }

        public event EventHandler Selected;

        public event EventHandler Deselected;

        public event EventHandler Selection;

        public event EventHandler<CancelEventArgs> Deselection;

        public T Item { get; private set; }

        public int Index
        {
            get
            {
                return index;
            }

            internal set
            {
                SetProperty(ref index, value, () => Index);
            }
        }

        public bool IsSelected
        {
            get
            {
                return isSelected;
            }

            set
            {
                if (value == isSelected || parent == null)
                {
                    return;
                }

                if (value)
                {
                    parent.ProcessItemSelectionRequest(this);
                }
                else
                {
                    parent.ProcessItemDeselectionRequest(this);
                }
            }
        }

        public bool IsSelectable
        {
            get
            {
                return isSelectable;
            }

            set
            {
                if (value == isSelectable || parent == null)
                {
                    return;
                }

                if (value)
                {
                    SetProperty(ref isSelectable, true, () => IsSelectable);
                    parent.ProcessItemEnable(this);
                }
                else
                {
                    parent.ProcessItemDisable(this);
                    SetProperty(ref isSelectable, false, () => IsSelectable);
                }
            }
        }

        internal void SetIsSelectedInternal(bool value)
        {
            SetProperty(ref isSelected, value, () => IsSelected);
        }

        internal void ProcessSelection()
        {
            OnSelection();
        }

        internal void ProcessSelected()
        {
            OnSelected();
        }

        internal bool ProcessDeselection()
        {
            return OnDeselection();
        }

        internal void ProcessDeselected()
        {
            OnDeselected();
        }

        protected virtual void OnSelection()
        {
            var handler = Selection;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        protected virtual void OnSelected()
        {
            var handler = Selected;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        protected virtual bool OnDeselection()
        {
            var handler = Deselection;
            if (handler != null)
            {
                var args = new CancelEventArgs();
                handler(this, args);
                return !args.Cancel;
            }

            return true;
        }

        protected virtual void OnDeselected()
        {
            var handler = Deselected;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }
}